<script setup lang="ts">
import { onMounted, ref, watch, watchEffect, nextTick } from 'vue'
import { useMainStore } from '@/store/index'
import { useMainLogin } from '@/store/user'
import { newFolder,searchFolderList,searchElementList,changeFolderSort,changeElementSort,changeFolder,changeFolderStatus,delFolder,delElement,changeElement,newGeom, getElementStat } from '@/api/plots'
import downloade from "@/api/downloade"
import * as mars3d from "mars3d"
import { billboard } from 'element-plus'
import icon from '@assets/image/ggtsg.png'
import { initPointPie } from '@utils/pie.ts'
import { ChartPieOne } from '@icon-park/vue-next'  //图标
import { Tree } from '@/types/serviceAddress'
import chooseNode from '@utils/chooseTreeNode.ts'
// 上传kml
import SceneControl from "@/utils/site.js"
import { files } from "@/api/plotsInfo"
import bus from '@/utils/eventBus'
import EVENTS from '@/utils/EVENTS'

const Cesium = mars3d.Cesium
const store = useMainStore()
const user = useMainLogin()
const colorList = ref<any>(['#05a5f1','#03b41b','#f19d23','#d9001b','#8401ff'])
const colorChecked = ref<string>('#05a5f1')
const dataSource = ref<any>()
const props = ref<any>({isLeaf: 'leaf'})
const billboard = ref<InstanceType<typeof billboard>>()
const treeExpandelKeys = ref<any>([])
const nodeId = ref<any>()
const folderId = ref<any>()
const childrenSort = ref<number>(0)
const filterText = ref<string>('')
// 传入饼图数据
const dataList = ref<any>([])
const dataStatShow = ref<boolean>(false)
const showAllData = ref<boolean>(true)
const newPointData = ref<any>()
const isDrawing = ref<boolean>(false)

onMounted(async () => {
  // 目标节点
  const targetNode = document.getElementById('listBox4');
  let height = targetNode.offsetHeight;
  let top2Bottom = window.innerHeight - targetNode.getBoundingClientRect().top -10

 // 创建一个 MutationObserver 实例
 const observer = new MutationObserver((mutationsList, observer) => {
   // 在每次 DOM 变化时触发的回调函数
   for (let mutation of mutationsList) {
     if (mutation.type === 'attributes'&& targetNode.offsetHeight!=height) {
      if(targetNode.offsetHeight < top2Bottom) {
        targetNode.style.top = '0px'
      }else {
        targetNode.style.top = (top2Bottom - targetNode.offsetHeight - 10) + 'px'
      }
     }
   }
 });

 // 配置 MutationObserver
 const config = { childList: true, attributes: true, subtree: true };

 // 开始观察目标节点
 observer.observe(targetNode, config);
})

/* 树型 */
//搜索
watch(filterText, (val) => {
  billboard.value!.filter(val)
})

const filterNode = (value: string, data: Tree, node: any) => {
  if (!value) return true
  return chooseNode(value, data, node)
}

const addClass = () => {
  var length = billboard.value.root.childNodes.length
  var tree = {name:length==0?'默认分组': '默认分组'+ length , type:'billboard',sort:length, children:[],isOpen:false,userId:user.userId,category:'其他'}
  // 待修改 提交数据库后返回可用结构插入到树结构中
  newFolder(tree).then(res => {
    if(res.code === 200) {
      tree.id = tree.folderId = res.data
      billboard.value.append(tree,billboard.value.root)
    }
  })
}

const dataStat = () => {
  dataStatShow.value = showAllData.value = true
  getElementByOters('billboard', false)
}

const getExcel = () => {
  downloade.getElementExcel('billboard', !showAllData.value)
}

const changeData = () => {
  showAllData.value = !showAllData.value
  if (showAllData.value) {
    getElementByOters('billboard', false)
  } else {
    getElementByOters('billboard', true)
  }
}

const getElementByOters = (type, trueOrFalse) => {
  getElementStat(type, trueOrFalse).then(res => {
    if (res.code === 200) {
      nextTick(() => {
        dataList.value = res.data
        initPointPie(dataList.value.elementStatisticTypeVo, dataList.value.totalCount, '个数/个:')
      })
    }
  })
}

const startDraw = () => {
  store.graphicOperate = '结束编辑'
  if(!folderId.value) {
    folderId.value = billboard.value.root.childNodes[0].data.folderId
    childrenSort.value = billboard.value.root.childNodes[0].childNodes.length
  }
  isDrawing.value = true
  window.graphicLayer.startDraw({
    name:"我的地标",
    type: "billboard",
    addHeight: 50,
    attr:{
        category:'其他',
        remark:'',
        folderId:folderId.value,
        childrenSort:childrenSort.value
    },
    style:{
        image:icon,
        pixelSize: 10,
        color: colorChecked.value,
        outlineColor:colorChecked.value,
        edittype:"billboard",
        label: {
          text: "我的地标",
          pixelOffsetY: -40,
          color: '#fff',
          outline:true,
          outlineColor: "#000",
          outlineWidth:4,
          setHeight:5,
          scaleByDistance:true,
          distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0,2500)
        }
    },
    success:function(graphic)  {
      let item = {
        name:"我的地标",
        type:"billboard",
        sort:childrenSort.value,
        folderId:folderId.value,
        graphicId:graphic._id,
        isOpen:true,
        // geom:JSON.stringify(graphic),
        geom:JSON.parse(JSON.stringify(graphic)),
        id:'',
        elementId:'',
        leaf: true
      }
      postKmlData(graphic, item)
    }
  })
}

// 新增时上传kml文件
const postKmlData = (graphic, item) => {
  var instance = SceneControl.getInstance()
  var filename = item.name + '.kml'
  const geojson = window.graphicLayer.getGraphicById(graphic._id).toGeoJSON()
  geojson.properties.geom = geojson.properties.remark = ''
  geojson.properties.style = JSON.stringify(geojson.properties.style)
  const data = instance.tokml(geojson)
  const blob = new Blob([data])
  var geofile = new File([blob], filename, {
    type: 'application/json',
    lastModified: Date.now()
  });
  files(geofile, '其他', graphic._id).then(res => {
    newPoint(graphic, item, res.data)
  })
}

// 新增点
const newPoint = (graphic, item, kmlData) => {
  let folderId = graphic.options.attr.folderId
  graphic.options.attr.ossId = kmlData.ossId
  graphic.options.attr.kmlName = kmlData.fileName
  graphic.options.attr.kmlUrl = kmlData.url
  graphic.options.attr.showNotes = false
  graphic.options.attr.geom = JSON.stringify(graphic)
  item.geom = JSON.stringify(graphic)
  item.userId = user.userId
  newGeom(item).then(res => {
    if(res.code === 200) {
      graphic.options.attr.elementId = item.elementId = item.id = res.data
      window.graphicLayer.startEditing(graphic)
      ElMessage({ type: 'success', message: '创建成功!' });
        if(billboard.value.getNode(folderId).loaded) {
        billboard.value.append(item, folderId)
        billboard.value.setChecked(res.data, true, true)
      }
      isDrawing.value = false
    }
  })
}

// 懒加载根节点
const loadNode = async (node, resolve) => {
  if (node.level == 0) {
    await loadTree(resolve)
  } else if (node.level == 1) {
    var folderId = node.data.folderId
    await searchElementList(folderId).then(async res=>{
      if(res.code === 200) {
        res.rows.forEach(async item => {
            var geom = JSON.parse(item.geom)
            item.graphicId = geom.id
            item.id = item.elementId
            item.leaf = true
          if (!window.graphicLayer.getGraphicById(item.graphicId) && item.isOpen) {
              await loadEntity(item)
            }
        })
        resolve(res.rows)
        res.rows.forEach(item => {
          billboard.value.setChecked(item.id,item.isOpen)
        })
      }
    })
  }
}
// 懒加载子节点
const loadTree = async (resolve) => {
  // 等待用户信息加载完成
  if (!user.userId) {
    await new Promise(resolve => {
      const unwatch = watch(() => user.userId, (newVal) => {
        if (newVal) {
          unwatch()
          resolve(true)
        }
      }, { immediate: true })
    })
  }

  searchFolderList('billboard',user.userId).then(res=>{
    if(res.code === 200) {
      if(res.rows.length>0) {
        res.rows.forEach(item => {
          item.isOpen ? treeExpandelKeys.value.push(item.folderId) : ''
          item.id = item.folderId
          item.children = []
        })
        resolve(res.rows)
      }else {
        addClass()
      }
    }
  })
}
// 加载实例
const loadEntity = (item) => {
  var geom = JSON.parse(item.geom)
  geom.attr.geom = ''
  geom.attr.remark = item.remark
  geom.attr.elementId = item.elementId
  geom.attr.category = item.category
  geom.attr.geom = JSON.parse(JSON.stringify(geom))
  geom.style.label.distanceDisplayCondition = true
  geom.style.label.distanceDisplayCondition_far = 2500
  geom.style.label.distanceDisplayCondition_near = 0
  const entity = new mars3d.graphic.BillboardEntity(geom)
  window.graphicLayer.addGraphic(entity)
}

const change = async (data, self, childSelect) => {
  if (data.graphicId) {
    data.isOpen = self
    data.isDelOss = 1
    if (!window.graphicLayer.getGraphicById(data.graphicId)) {
        await loadEntity(data)
    } else {
      window.graphicLayer.getGraphicById(data.graphicId).show = self
    }
    // changeElement(data)
  } else {
    data.isOpen = self || childSelect ? true : false
  }
}

const changeCheck = (data,self) => {
  if(data.elementId) {
    data.used = user.userId
    changeElement(data)
  }else {
    changeFolderStatus(data.folderId)
  }
}

// 限制节点拖动
const collapse = (moveNode, inNode, type) => {
  if(moveNode.level == 1 && inNode.level == 1) {
      // 四种情况
      if (moveNode.nextSibling == undefined) {
          return type == 'prev';
      } else if (inNode.nextSibling == undefined) {
          return type == 'next';
      } else if (moveNode.nextSibling.id !== inNode.id) {
          return type == 'prev';
      } else {
          return type == 'next';
      }
  }
  // 二级拖动到二级
  if (moveNode.level == 2 && inNode.level == 2) {
      // 四种情况
      if (moveNode.nextSibling == undefined) {
          return type == 'prev';
      } else if (inNode.nextSibling == undefined) {
          return type == 'next';
      } else if (moveNode.nextSibling.id !== inNode.id) {
          return type == 'prev';
      } else {
          return type == 'next';
      }
  }
  // 二级拖动到一级
  if (moveNode.level == 2 && inNode.level == 1) {
      // 四种情况
      return type == 'inner';
  }
}
// 控制节点排序
const nodedrop = (before,after,inner) => {
  var flag = false
  billboard.value.getNode(before.data.folderId).childNodes.forEach(item =>{
    item.checked? flag = true:''
  })
  billboard.value.setChecked(before.data.folderId,flag)
  before.checked? billboard.value.setChecked(before.data.id,true):''
    if(inner === 'inner') {
        before.data.folderId = after.data.folderId
        before.data.sort = after.data.children.length - 1
        let graphic = window.graphicLayer.getGraphicById(before.data.graphicId)
        graphic.options.attr.folderId = after.data.folderId
        let geom = JSON.parse(graphic.options.attr.geom)
        geom.attr.folderId = after.data.folderId
        let attrGeom = JSON.stringify(geom)
        graphic.options.attr.geom = attrGeom
        before.data.userId = user.userId
        changeElement(before.data)
    }else {
        // 同级树下拖动排序
        var childNodes = after.parent.childNodes
        var arr=[]
        if(before.level == 1 && after.level == 1) {
          childNodes.forEach((item,index) => {
            item.data.sort = index
            arr.push(item.data)
          })
          changeFolderSort(arr)
        }else if(before.level == 2 && after.level == 2) {
          childNodes.forEach((item,index) => {
            item.data.sort = index
            item.data.folderId = after.data.folderId
            arr.push(item.data)
          })
          changeElementSort(arr)
        }
    }
}

// 开始标题编辑
const onInputBlur = (data) => {
  nodeId.value = -1
  if (data.name.length == 0) data.name = "";
  data.name = data.name.replace(/\n/g, "<br />");
  changeFolder(data).then( (res:any) => {
    res.code === 200?ElMessage({message: '文件夹名称修改成功!',type: 'success'}):''
  })
}

// 移除文件夹
const removefiles = (node, data) => {
  folderId.value = ''
  ElMessageBox.confirm('是否删除当前分区以及分区下的标注?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
  }).then(() => {
      var folderId = data.folderId;
      delFolder(folderId).then(res => {
        if(res.code === 200) {
          try {window.graphicLayer.getGraphicsByAttr(data.folderId,'folderId').forEach(grapgic => {grapgic.remove()})} catch (error) {}
          billboard.value.remove(node)
          store.graphicOperate = '结束编辑'
          ElMessage.success('文件夹删除成功')
        }
      })
  }).catch(() => {
      ElMessage({type: 'info',message: '已取消删除'});
  });
}

// 移除要素
const remove = (node,data) => {
  ElMessageBox.confirm('是否删除当前要素?','提示',{
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    }
  ).then(() => {
      delElement(data.elementId).then(res=> {
        if(res.code === 200) {
          store.graphicOperate = '结束编辑'
          billboard.value.remove(data)
          try {window.graphicLayer.getGraphicById(data.graphicId).remove()} catch (error) {}
          ElMessage({type: 'success',message: '删除成功!'});
        }
      })
  }).catch(() => {
      ElMessage({type: 'info',message: '已取消删除'});
  });
}

// 相机移动至要素
const flyToGraphic = (data) => {
  var graphic = window.graphicLayer.getGraphicById(data.graphicId);
  graphic.flyTo({radius:300})
}

const removeGraphic = () => {
  if(billboard.value.getNode(window.graphicLayer.getGraphicById(store.graphicId).options.attr.elementId)) {
    billboard.value.remove(window.graphicLayer.getGraphicById(store.graphicId).options.attr.elementId)
  }
  if(window.graphicLayer.getGraphicById(store.graphicId)) {
    window.graphicLayer.getGraphicById(store.graphicId).remove()
  }
  store.graphicOperate = '结束编辑'
}

const editGraphic = () => {
  if(billboard.value.getNode(window.graphicLayer.getGraphicById(store.graphicId).options.attr.elementId)) {
    billboard.value.getNode(window.graphicLayer.getGraphicById(store.graphicId).options.attr.elementId).data.name = window.graphicLayer.getGraphicById(store.graphicId).options.name
    store.graphicOperate = '结束编辑'
  }
}

const startEdit = (data) => {
  window.graphicLayer.stopEditing()
  if(store.saved){
    try {
      window.graphicLayer.getGraphicById(data.graphicId).startEditing()
    } catch (error) {
      loadEntity(data)
      window.graphicLayer.getGraphicById(data.graphicId).startEditing()
    }
    if(!data.isOpen) {
      data.isOpen = !data.isOpen
      billboard.value.setChecked(data.id,data.isOpen)
    }
    store.graphicId = data.graphicId
    store.graphicOperate = '开始编辑'
  }
}

// 将文件夹下面的要素导出为kml
const downLoadAllObj = (data) => {
  downloade.getElementToKml(data.folderId, data.name)
}

bus.on(EVENTS.SENDTOBROTHER, (data) => {
  store.graphicOperate = '结束编辑'
  if(!folderId.value) {
    folderId.value = billboard.value.root.childNodes[0].data.folderId
    childrenSort.value = billboard.value.root.childNodes[0].childNodes.length
  }
  isDrawing.value = true
  const graphic = new mars3d.graphic.BillboardEntity({
    name:"坐标定位",
    position:data,
    attr:{
        category:'其他',
        remark:'',
        folderId:folderId.value,
        childrenSort:childrenSort.value
    },
    style:{
        image:icon,
        pixelSize: 10,
        color: colorChecked.value,
        outlineColor:colorChecked.value,
        edittype:"billboard",
        label: {
          text: "坐标定位",
          pixelOffsetY: -40,
          color: '#fff',
          outline:true,
          outlineColor: "#000",
          outlineWidth:4,
          setHeight:5,
          scaleByDistance:true,
          distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0,2500)
        }
    },
    flyTo:true
  })
  window.graphicLayer.addGraphic(graphic)
  let item = {
    name:"坐标定位",
    type:"billboard",
    sort:childrenSort.value,
    folderId:folderId.value,
    graphicId:graphic._id,
    isOpen:true,
    geom:JSON.parse(JSON.stringify(graphic)),
    id:'',
    elementId:'',
    leaf: true
  }
  postKmlData(graphic, item)
})

watchEffect(() => {
  if(store.graphicOperate == '删除'&&store.type=='billboard')removeGraphic();
  if(store.graphicOperate == '修改'&&store.type=='billboard')editGraphic();
  if(store.activeBtn!= 5)folderId.value = ''
})

</script>

<template>
  <div class="TabbarBtn">
    <div>
      <el-tooltip
        class="box-item"
        effect="dark"
        content="标注"
        placement="left"
      >
      <div :class="store.activeBtn==6?'iconBox show':'iconBox'" @click="[store.activeBtn==6?store.activeBtn=0:store.activeBtn=6]">
        <img src="@/assets/image/dian.png" alt="">
      </div>
      </el-tooltip>
    </div>
    <div :class="store.activeBtn==6?'btnTooltip show':'btnTooltip'" id="listBox4">
      <span class="listBox">
        <i @click="store.activeBtn=0" class="iconfont icon-cuo" style="position: absolute;right: 10px; top: 10px;cursor: pointer;"></i>
        <div class="listBoxHeader">
          <span @click="addClass()"><img src="@/assets/image/addFile.png" alt=""></span>
          <!-- <span class="addfolder" @click="dataStat"><chart-pie-one theme="outline" size="22" fill="#fff" style="display: flex;margin-right: 3px;"/>统计</span> -->
        </div>

        <div style="clear: both;padding: 20px 0;">
          <el-input v-model="filterText" placeholder="请输入名称搜索" />
          <el-scrollbar>
            <el-tree
              ref="billboard"
              :props="props"
              :data="dataSource"
              node-key="id"
              show-checkbox
              draggable
              lazy
              :load="loadNode"
              @check-change="change"
              @check="changeCheck"
              :default-expanded-keys="treeExpandelKeys"
              :allow-drop="collapse"
              @node-drop="nodedrop"
              :expand-on-click-node="false"
              :filter-node-method="filterNode"
            >
              <template #default="{ node, data }">
                  <div v-if="node.level == 1" :style="folderId == data.folderId && node.level == 1? 'background:#666;width: 100%;':'width: 100%;'">
                    <div class="treeNode" v-show="nodeId != node.id">
                      <span class="tree1Title" @click="[folderId = data.folderId,childrenSort = node.childNodes.length]">{{ data.name }}</span>
                      <div style="display: flex;align-items: center;"><img @click="downLoadAllObj(data)" class="iconfont" style="width: 1rem;" src="@/assets/image/download.png" alt=""><img @click="[nodeId = node.id,folderId='']" style="width: 16px;" src="@/assets/image/elementEditor.png" alt=""><i v-show="node.parent.childNodes.length!=1" @click="removefiles(node,data)" class="iconfont icon-cuo"></i></div>
                    </div>
                    <div class="treeNode" v-show="nodeId == node.id">
                      <div class="textInputWrapper">
                        <input placeholder="Type Here" type="text" class="textInput" v-model="data.name" @keydown.enter="onInputBlur(data)">
                      </div>
                      <i @click="onInputBlur(data)" class="iconfont icon-xuanze-"></i>
                    </div>
                  </div>
                  <div :class="store.graphicId==data.graphicId?'treeNode active':'treeNode'" v-else>
                    <span class="tree2Title" @click.stop="startEdit(data)">{{ data.name }}</span>
                    <div style="display: flex;align-items: center;">
                      <img @click.stop="flyToGraphic(data)"  style="width: 16px;    margin-left: 5px;" src="@/assets/image/dingwei.png" alt="">
                      <span><i @click.stop="remove(node, data)" class="iconfont icon-cuo"></i></span>
                    </div>
                  </div>
              </template>
            </el-tree>
          </el-scrollbar>
        </div>

        <div class="color_box">
          <div id="fifth-element-introduction" @click="startDraw()"><img src="@/assets/image/editor.png" alt=""></div>
            <div class="color_outline" v-for="(item,index) in colorList" :key="index">
                <span class="bg">
                    <span class="color" :style="!isDrawing?'background-color:' + item:'background-color:' + item+';pointer-events:none;'"  @click="colorChecked = item">
                        <span class="checked" v-if="colorChecked == item? true:false"><i style="font-size: 20px;" class="iconfont icon-xuanze-"></i></span>
                    </span>
                </span>
            </div>
        </div>
      </span>
    </div>
  </div>

  <div class="baseInfoBox" v-show="dataStatShow">
    <div class="shadow" @click="dataStatShow = false"></div>
    <div class="infoBox">
      <div class="topInfoBox">
        <div class="topInfoBox-left">
          <span v-if="showAllData" class="topInfoBox-left-title">所有点的统计</span>
          <span v-else class="topInfoBox-left-title">已打开点的统计</span>
          <el-tooltip
            class="box-item"
            effect="dark"
            :content="showAllData?'“所有点的统计”是统计平台中所有的要素；':'“已打开点的统计”是在统计地图上所有处于打开状态的要素。'"
            placement="top-start"
          >
            <div class="addfolder" style="margin-left: 10px;"  @click="changeData">切换统计方式</div>
          </el-tooltip>
        </div>
        <div style="display: flex;align-items: center;">
          <div class="addfolder" style="margin-right: 10px;" @click="getExcel">导出表格</div>
          <i class="iconfont icon-cuo icon-size"  @click="dataStatShow = false"></i>
        </div>
      </div>
      <div class="element-data">
        <div id="pie-data-count-point"></div>
        <div id="form-data">
          <div class="form-data-head">
            <span>点统计表(点的总数：{{ dataList.totalCount }}个)</span>
            <!-- <span style="margin-left: 20px;">点的总数{{ dataList.totalCount }}个</span> -->
          </div>
          <el-table class="form-data-table" :data="dataList.elementStatisticTypeVo" style="width: 100%;" height="97%">
            <el-table-column prop="category" label="类型" />
            <el-table-column prop="count" label="个数/个" />
          </el-table>
        </div>
      </div>
    </div>
  </div>

</template>

<style scoped>
.btn {
    border-radius: 5px 5px 0 0;
}
</style>
